Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
56.52% covered (warning)
56.52%
13 / 23
CRAP
96.52% covered (success)
96.52%
1165 / 1207
PptCharts
0.00% covered (danger)
0.00%
0 / 1
56.52% covered (warning)
56.52%
13 / 23
215
96.52% covered (success)
96.52%
1165 / 1207
 render
0.00% covered (danger)
0.00%
0 / 1
5.02
90.91% covered (success)
90.91%
10 / 11
 writeChart
0.00% covered (danger)
0.00%
0 / 1
8.23
84.72% covered (warning)
84.72%
61 / 72
 writeSpreadsheet
0.00% covered (danger)
0.00%
0 / 1
6.01
93.10% covered (success)
93.10%
27 / 29
 writeElementWithValAttribute
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
4 / 4
 writeSingleValueOrReference
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
16 / 16
 writeMultipleValuesOrReference
100.00% covered (success)
100.00%
1 / 1
6
100.00% covered (success)
100.00%
26 / 26
 writeTitle
100.00% covered (success)
100.00%
1 / 1
4
100.00% covered (success)
100.00%
48 / 48
 writePlotArea
100.00% covered (success)
100.00%
1 / 1
12
100.00% covered (success)
100.00%
28 / 28
 writeLegend
100.00% covered (success)
100.00%
1 / 1
5
100.00% covered (success)
100.00%
48 / 48
 writeLayout
0.00% covered (danger)
0.00%
0 / 1
5.27
77.78% covered (warning)
77.78%
21 / 27
 writeTypeArea
0.00% covered (danger)
0.00%
0 / 1
9.02
93.48% covered (success)
93.48%
43 / 46
 writeTypeBar
0.00% covered (danger)
0.00%
0 / 1
17.10
93.07% covered (success)
93.07%
94 / 101
 writeTypeBar3D
0.00% covered (danger)
0.00%
0 / 1
15
96.74% covered (success)
96.74%
89 / 92
 writeTypeDoughnut
0.00% covered (danger)
0.00%
0 / 1
20
95.29% covered (success)
95.29%
81 / 85
 writeTypePie
0.00% covered (danger)
0.00%
0 / 1
15.03
94.94% covered (success)
94.94%
75 / 79
 writeTypePie3D
100.00% covered (success)
100.00%
1 / 1
13
100.00% covered (success)
100.00%
76 / 76
 writeTypeLine
100.00% covered (success)
100.00%
1 / 1
13
100.00% covered (success)
100.00%
81 / 81
 writeTypeRadar
100.00% covered (success)
100.00%
1 / 1
13
100.00% covered (success)
100.00%
82 / 82
 writeTypeScatter
100.00% covered (success)
100.00%
1 / 1
16
100.00% covered (success)
100.00%
85 / 85
 writeChartRelationships
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
8 / 8
 writeSeriesMarker
100.00% covered (success)
100.00%
1 / 1
4
100.00% covered (success)
100.00%
19 / 19
 writeAxis
0.00% covered (danger)
0.00%
0 / 1
23
99.29% covered (success)
99.29%
139 / 140
 writeAxisGridlines
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
4 / 4
1<?php
2/**
3 * This file is part of PHPPresentation - A pure PHP library for reading and writing
4 * presentations documents.
5 *
6 * PHPPresentation is free software distributed under the terms of the GNU Lesser
7 * General Public License version 3 as published by the Free Software Foundation.
8 *
9 * For the full copyright and license information, please read the LICENSE
10 * file that was distributed with this source code. For the full list of
11 * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors.
12 *
13 * @see        https://github.com/PHPOffice/PHPPresentation
14 *
15 * @copyright   2009-2015 PHPPresentation contributors
16 * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
17 */
18
19declare(strict_types=1);
20
21namespace PhpOffice\PhpPresentation\Writer\PowerPoint2007;
22
23use PhpOffice\Common\Adapter\Zip\ZipInterface;
24use PhpOffice\Common\Drawing as CommonDrawing;
25use PhpOffice\Common\XMLWriter;
26use PhpOffice\PhpPresentation\Exception\FileRemoveException;
27use PhpOffice\PhpPresentation\Exception\UndefinedChartTypeException;
28use PhpOffice\PhpPresentation\PhpPresentation;
29use PhpOffice\PhpPresentation\Shape\Chart;
30use PhpOffice\PhpPresentation\Shape\Chart\Gridlines;
31use PhpOffice\PhpPresentation\Shape\Chart\Legend;
32use PhpOffice\PhpPresentation\Shape\Chart\PlotArea;
33use PhpOffice\PhpPresentation\Shape\Chart\Title;
34use PhpOffice\PhpPresentation\Shape\Chart\Type\Area;
35use PhpOffice\PhpPresentation\Shape\Chart\Type\Bar;
36use PhpOffice\PhpPresentation\Shape\Chart\Type\Bar3D;
37use PhpOffice\PhpPresentation\Shape\Chart\Type\Doughnut;
38use PhpOffice\PhpPresentation\Shape\Chart\Type\Line;
39use PhpOffice\PhpPresentation\Shape\Chart\Type\Pie;
40use PhpOffice\PhpPresentation\Shape\Chart\Type\Pie3D;
41use PhpOffice\PhpPresentation\Shape\Chart\Type\Radar;
42use PhpOffice\PhpPresentation\Shape\Chart\Type\Scatter;
43use PhpOffice\PhpPresentation\Style\Border;
44use PhpOffice\PhpPresentation\Style\Fill;
45use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
46use PhpOffice\PhpSpreadsheet\IOFactory;
47use PhpOffice\PhpSpreadsheet\Spreadsheet;
48
49class PptCharts extends AbstractDecoratorWriter
50{
51    /**
52     * @throws FileRemoveException
53     */
54    public function render(): ZipInterface
55    {
56        for ($i = 0; $i < $this->getDrawingHashTable()->count(); ++$i) {
57            $shape = $this->getDrawingHashTable()->getByIndex($i);
58            if ($shape instanceof Chart) {
59                $this->getZip()->addFromString('ppt/charts/' . $shape->getIndexedFilename(), $this->writeChart($shape));
60
61                if ($shape->hasIncludedSpreadsheet()) {
62                    $this->getZip()->addFromString('ppt/charts/_rels/' . $shape->getIndexedFilename() . '.rels', $this->writeChartRelationships($shape));
63                    $pFilename = tempnam(sys_get_temp_dir(), 'PhpSpreadsheet');
64                    $this->getZip()->addFromString('ppt/embeddings/' . $shape->getIndexedFilename() . '.xlsx', $this->writeSpreadsheet($this->getPresentation(), $shape, $pFilename . '.xlsx'));
65
66                    // remove temp file
67                    if (false === @unlink($pFilename)) {
68                        throw new FileRemoveException($pFilename);
69                    }
70                }
71            }
72        }
73
74        return $this->getZip();
75    }
76
77    /**
78     * Write chart to XML format.
79     *
80     * @return string XML Output
81     */
82    protected function writeChart(Chart $chart): string
83    {
84        // Create XML writer
85        $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
86
87        // XML header
88        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
89
90        // c:chartSpace
91        $objWriter->startElement('c:chartSpace');
92        $objWriter->writeAttribute('xmlns:c', 'http://schemas.openxmlformats.org/drawingml/2006/chart');
93        $objWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main');
94        $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
95
96        // c:date1904
97        $objWriter->startElement('c:date1904');
98        $objWriter->writeAttribute('val', '1');
99        $objWriter->endElement();
100
101        // c:lang
102        $objWriter->startElement('c:lang');
103        $objWriter->writeAttribute('val', 'en-US');
104        $objWriter->endElement();
105
106        // c:chart
107        $objWriter->startElement('c:chart');
108
109        // Title?
110        if ($chart->getTitle()->isVisible()) {
111            // Write title
112            $this->writeTitle($objWriter, $chart->getTitle());
113        }
114
115        // c:autoTitleDeleted
116        $objWriter->startElement('c:autoTitleDeleted');
117        $objWriter->writeAttribute('val', $chart->getTitle()->isVisible() ? '0' : '1');
118        $objWriter->endElement();
119
120        // c:view3D
121        $objWriter->startElement('c:view3D');
122
123        // c:rotX
124        $objWriter->startElement('c:rotX');
125        $objWriter->writeAttribute('val', $chart->getView3D()->getRotationX());
126        $objWriter->endElement();
127
128        // c:hPercent
129        $hPercent = $chart->getView3D()->getHeightPercent();
130        $objWriter->writeElementIf(null != $hPercent, 'c:hPercent', 'val', $hPercent);
131
132        // c:rotY
133        $objWriter->startElement('c:rotY');
134        $objWriter->writeAttribute('val', $chart->getView3D()->getRotationY());
135        $objWriter->endElement();
136
137        // c:depthPercent
138        $objWriter->startElement('c:depthPercent');
139        $objWriter->writeAttribute('val', $chart->getView3D()->getDepthPercent());
140        $objWriter->endElement();
141
142        // c:rAngAx
143        $objWriter->startElement('c:rAngAx');
144        $objWriter->writeAttribute('val', $chart->getView3D()->hasRightAngleAxes() ? '1' : '0');
145        $objWriter->endElement();
146
147        // c:perspective
148        $objWriter->startElement('c:perspective');
149        $objWriter->writeAttribute('val', $chart->getView3D()->getPerspective());
150        $objWriter->endElement();
151
152        $objWriter->endElement();
153
154        // Write plot area
155        $this->writePlotArea($objWriter, $chart->getPlotArea(), $chart);
156
157        // Legend?
158        if ($chart->getLegend()->isVisible()) {
159            // Write legend
160            $this->writeLegend($objWriter, $chart->getLegend());
161        }
162
163        // c:plotVisOnly
164        $objWriter->startElement('c:plotVisOnly');
165        $objWriter->writeAttribute('val', '1');
166        $objWriter->endElement();
167
168        // c:dispBlanksAs
169        $objWriter->startElement('c:dispBlanksAs');
170        $objWriter->writeAttribute('val', $chart->getDisplayBlankAs());
171        $objWriter->endElement();
172
173        $objWriter->endElement();
174
175        // c:spPr
176        $objWriter->startElement('c:spPr');
177
178        // Fill
179        $this->writeFill($objWriter, $chart->getFill());
180
181        // Border
182        if (Border::LINE_NONE != $chart->getBorder()->getLineStyle()) {
183            $this->writeBorder($objWriter, $chart->getBorder(), '');
184        }
185
186        // Shadow
187        if ($chart->getShadow()->isVisible()) {
188            // a:effectLst
189            $objWriter->startElement('a:effectLst');
190
191            // a:outerShdw
192            $objWriter->startElement('a:outerShdw');
193            $objWriter->writeAttribute('blurRad', CommonDrawing::pixelsToEmu($chart->getShadow()->getBlurRadius()));
194            $objWriter->writeAttribute('dist', CommonDrawing::pixelsToEmu($chart->getShadow()->getDistance()));
195            $objWriter->writeAttribute('dir', CommonDrawing::degreesToAngle((int) $chart->getShadow()->getDirection()));
196            $objWriter->writeAttribute('algn', $chart->getShadow()->getAlignment());
197            $objWriter->writeAttribute('rotWithShape', '0');
198
199            $this->writeColor($objWriter, $chart->getShadow()->getColor(), $chart->getShadow()->getAlpha());
200
201            $objWriter->endElement();
202
203            $objWriter->endElement();
204        }
205
206        $objWriter->endElement();
207
208        // External data?
209        if ($chart->hasIncludedSpreadsheet()) {
210            // c:externalData
211            $objWriter->startElement('c:externalData');
212            $objWriter->writeAttribute('r:id', 'rId1');
213
214            // c:autoUpdate
215            $objWriter->startElement('c:autoUpdate');
216            $objWriter->writeAttribute('val', '0');
217            $objWriter->endElement();
218
219            $objWriter->endElement();
220        }
221
222        $objWriter->endElement();
223
224        // Return
225        return $objWriter->getData();
226    }
227
228    /**
229     * Write chart to XML format.
230     *
231     * @return string String output
232     *
233     * @throws FileRemoveException
234     */
235    protected function writeSpreadsheet(PhpPresentation $presentation, Chart $chart, string $tempName): string
236    {
237        // Create new spreadsheet
238        $spreadsheet = new Spreadsheet();
239
240        // Set properties
241        $title = $chart->getTitle()->getText();
242        if (0 == strlen($title)) {
243            $title = 'Chart';
244        }
245        $spreadsheet->getProperties()
246            ->setCreator(
247                $presentation->getDocumentProperties()->getCreator())->setLastModifiedBy(
248                    $presentation->getDocumentProperties()->getLastModifiedBy()
249                )
250            ->setTitle($title);
251
252        // Add chart data
253        $sheet = $spreadsheet->setActiveSheetIndex(0);
254        $sheet->setTitle('Sheet1');
255
256        // Write series
257        $seriesIndex = 0;
258        foreach ($chart->getPlotArea()->getType()->getSeries() as $series) {
259            // Title
260            $sheet->setCellValueByColumnAndRow(1 + $seriesIndex, 1, $series->getTitle());
261
262            // X-axis
263            $axisXData = array_keys($series->getValues());
264            $numAxisXData = count($axisXData);
265            for ($i = 0; $i < $numAxisXData; ++$i) {
266                $sheet->setCellValueByColumnAndRow(0, $i + 2, $axisXData[$i]);
267            }
268
269            // Y-axis
270            $axisYData = array_values($series->getValues());
271            $numAxisYData = count($axisYData);
272            for ($i = 0; $i < $numAxisYData; ++$i) {
273                $sheet->setCellValueByColumnAndRow(1 + $seriesIndex, $i + 2, $axisYData[$i]);
274            }
275
276            ++$seriesIndex;
277        }
278
279        // Save to string
280        $writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
281        $writer->save($tempName);
282
283        // Load file in memory
284        $returnValue = file_get_contents($tempName);
285        if (false === @unlink($tempName)) {
286            throw new FileRemoveException($tempName);
287        }
288
289        return $returnValue;
290    }
291
292    /**
293     * Write element with value attribute.
294     *
295     * @param XMLWriter $objWriter XML Writer
296     */
297    protected function writeElementWithValAttribute(XMLWriter $objWriter, string $elementName, string $value): void
298    {
299        $objWriter->startElement($elementName);
300        $objWriter->writeAttribute('val', $value);
301        $objWriter->endElement();
302    }
303
304    /**
305     * Write single value or reference.
306     *
307     * @param XMLWriter $objWriter XML Writer
308     */
309    protected function writeSingleValueOrReference(XMLWriter $objWriter, bool $isReference, string $value, string $reference): void
310    {
311        if (!$isReference) {
312            // Value
313            $objWriter->writeElement('c:v', $value);
314
315            return;
316        }
317
318        // Reference and cache
319        // c:strRef
320        $objWriter->startElement('c:strRef');
321        // c:strRef/c:f
322        $objWriter->writeElement('c:f', $reference);
323        // c:strRef/c:strCache
324        $objWriter->startElement('c:strCache');
325        // c:strRef/c:strCache/c:ptCount
326        $objWriter->startElement('c:ptCount');
327        $objWriter->writeAttribute('val', '1');
328        $objWriter->endElement();
329
330        // c:strRef/c:strCache/c:pt
331        $objWriter->startElement('c:pt');
332        $objWriter->writeAttribute('idx', '0');
333        // c:strRef/c:strCache/c:pt/c:v
334        $objWriter->writeElement('c:v', $value);
335        // c:strRef/c:strCache/c:pt
336        $objWriter->endElement();
337        // c:strRef/c:strCache
338        $objWriter->endElement();
339        // c:strRef
340        $objWriter->endElement();
341    }
342
343    /**
344     * Write series value or reference.
345     *
346     * @param XMLWriter $objWriter XML Writer
347     * @param array<int, mixed> $values
348     */
349    protected function writeMultipleValuesOrReference(XMLWriter $objWriter, bool $isReference, array $values, string $reference): void
350    {
351        // c:strLit / c:numLit
352        // c:strRef / c:numRef
353        $referenceType = ($isReference ? 'Ref' : 'Lit');
354        $dataType = is_numeric($values[0]) ? 'num' : 'str';
355        $objWriter->startElement('c:' . $dataType . $referenceType);
356
357        $numValues = count($values);
358        if (!$isReference) {
359            // Value
360
361            // c:ptCount
362            $objWriter->startElement('c:ptCount');
363            $objWriter->writeAttribute('val', count($values));
364            $objWriter->endElement();
365
366            // Add points
367            for ($i = 0; $i < $numValues; ++$i) {
368                // c:pt
369                $objWriter->startElement('c:pt');
370                $objWriter->writeAttribute('idx', $i);
371                $objWriter->writeElement('c:v', strval($values[$i]));
372                $objWriter->endElement();
373            }
374        } else {
375            // Reference
376            $objWriter->writeElement('c:f', $reference);
377            $objWriter->startElement('c:' . $dataType . 'Cache');
378
379            // c:ptCount
380            $objWriter->startElement('c:ptCount');
381            $objWriter->writeAttribute('val', count($values));
382            $objWriter->endElement();
383
384            // Add points
385            for ($i = 0; $i < $numValues; ++$i) {
386                // c:pt
387                $objWriter->startElement('c:pt');
388                $objWriter->writeAttribute('idx', $i);
389                $objWriter->writeElement('c:v', strval($values[$i]));
390                $objWriter->endElement();
391            }
392
393            $objWriter->endElement();
394        }
395
396        $objWriter->endElement();
397    }
398
399    /**
400     * Write Title
401     */
402    protected function writeTitle(XMLWriter $objWriter, Title $subject): void
403    {
404        // c:title
405        $objWriter->startElement('c:title');
406
407        // c:tx
408        $objWriter->startElement('c:tx');
409
410        // c:rich
411        $objWriter->startElement('c:rich');
412
413        // a:bodyPr
414        $objWriter->writeElement('a:bodyPr', null);
415
416        // a:lstStyle
417        $objWriter->writeElement('a:lstStyle', null);
418
419        // a:p
420        $objWriter->startElement('a:p');
421
422        // a:pPr
423        $objWriter->startElement('a:pPr');
424        $objWriter->writeAttribute('algn', $subject->getAlignment()->getHorizontal());
425        $objWriter->writeAttribute('fontAlgn', $subject->getAlignment()->getVertical());
426        $objWriter->writeAttribute('marL', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginLeft()));
427        $objWriter->writeAttribute('marR', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginRight()));
428        $objWriter->writeAttribute('indent', CommonDrawing::pixelsToEmu($subject->getAlignment()->getIndent()));
429        $objWriter->writeAttribute('lvl', $subject->getAlignment()->getLevel());
430
431        // a:defRPr
432        $objWriter->writeElement('a:defRPr', null);
433
434        $objWriter->endElement();
435
436        // a:r
437        $objWriter->startElement('a:r');
438
439        // a:rPr
440        $objWriter->startElement('a:rPr');
441        $objWriter->writeAttribute('lang', 'en-US');
442        $objWriter->writeAttribute('dirty', '0');
443        $objWriter->writeAttribute('b', ($subject->getFont()->isBold() ? 'true' : 'false'));
444        $objWriter->writeAttribute('i', ($subject->getFont()->isItalic() ? 'true' : 'false'));
445        $objWriter->writeAttribute('strike', ($subject->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
446        $objWriter->writeAttribute('sz', ($subject->getFont()->getSize() * 100));
447        $objWriter->writeAttribute('u', $subject->getFont()->getUnderline());
448        $objWriter->writeAttributeIf($subject->getFont()->isSuperScript(), 'baseline', '300000');
449        $objWriter->writeAttributeIf($subject->getFont()->isSubScript(), 'baseline', '-250000');
450
451        // Font - a:solidFill
452        $objWriter->startElement('a:solidFill');
453
454        $this->writeColor($objWriter, $subject->getFont()->getColor());
455
456        $objWriter->endElement();
457
458        // Font - a:latin
459        $objWriter->startElement('a:latin');
460        $objWriter->writeAttribute('typeface', $subject->getFont()->getName());
461        $objWriter->endElement();
462
463        $objWriter->endElement();
464
465        // a:t
466        $objWriter->writeElement('a:t', $subject->getText());
467
468        $objWriter->endElement();
469
470        // a:endParaRPr
471        $objWriter->startElement('a:endParaRPr');
472        $objWriter->writeAttribute('lang', 'en-US');
473        $objWriter->writeAttribute('dirty', '0');
474        $objWriter->endElement();
475
476        $objWriter->endElement();
477
478        $objWriter->endElement();
479
480        $objWriter->endElement();
481
482        // Write layout
483        $this->writeLayout($objWriter, $subject);
484
485        // c:overlay
486        $objWriter->startElement('c:overlay');
487        $objWriter->writeAttribute('val', '0');
488        $objWriter->endElement();
489
490        $objWriter->endElement();
491    }
492
493    /**
494     * Write Plot Area.
495     *
496     * @param XMLWriter $objWriter XML Writer
497     *
498     * @throws UndefinedChartTypeException
499     */
500    protected function writePlotArea(XMLWriter $objWriter, PlotArea $subject, Chart $chart): void
501    {
502        // c:plotArea
503        $objWriter->startElement('c:plotArea');
504
505        // Write layout
506        $this->writeLayout($objWriter, $subject);
507
508        // Write chart
509        $chartType = $subject->getType();
510        if ($chartType instanceof Area) {
511            $this->writeTypeArea($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
512        } elseif ($chartType instanceof Bar) {
513            $this->writeTypeBar($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
514        } elseif ($chartType instanceof Bar3D) {
515            $this->writeTypeBar3D($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
516        } elseif ($chartType instanceof Doughnut) {
517            $this->writeTypeDoughnut($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
518        } elseif ($chartType instanceof Pie) {
519            $this->writeTypePie($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
520        } elseif ($chartType instanceof Pie3D) {
521            $this->writeTypePie3D($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
522        } elseif ($chartType instanceof Line) {
523            $this->writeTypeLine($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
524        } elseif ($chartType instanceof Radar) {
525            $this->writeTypeRadar($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
526        } elseif ($chartType instanceof Scatter) {
527            $this->writeTypeScatter($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
528        } else {
529            throw new UndefinedChartTypeException();
530        }
531
532        // Write X axis?
533        if ($chartType->hasAxisX()) {
534            $this->writeAxis($objWriter, $subject->getAxisX(), Chart\Axis::AXIS_X, $chartType);
535        }
536
537        // Write Y axis?
538        if ($chartType->hasAxisY()) {
539            $this->writeAxis($objWriter, $subject->getAxisY(), Chart\Axis::AXIS_Y, $chartType);
540        }
541
542        $objWriter->endElement();
543    }
544
545    /**
546     * Write Legend.
547     *
548     * @param XMLWriter $objWriter XML Writer
549     * @param Chart\Legend $subject
550     */
551    protected function writeLegend(XMLWriter $objWriter, Legend $subject): void
552    {
553        // c:legend
554        $objWriter->startElement('c:legend');
555
556        // c:legendPos
557        $objWriter->startElement('c:legendPos');
558        $objWriter->writeAttribute('val', $subject->getPosition());
559        $objWriter->endElement();
560
561        // Write layout
562        $this->writeLayout($objWriter, $subject);
563
564        // c:overlay
565        $objWriter->startElement('c:overlay');
566        $objWriter->writeAttribute('val', '0');
567        $objWriter->endElement();
568
569        // c:spPr
570        $objWriter->startElement('c:spPr');
571
572        // Fill
573        $this->writeFill($objWriter, $subject->getFill());
574
575        // Border
576        if (Border::LINE_NONE != $subject->getBorder()->getLineStyle()) {
577            $this->writeBorder($objWriter, $subject->getBorder(), '');
578        }
579
580        $objWriter->endElement();
581
582        // c:txPr
583        $objWriter->startElement('c:txPr');
584
585        // a:bodyPr
586        $objWriter->writeElement('a:bodyPr', null);
587
588        // a:lstStyle
589        $objWriter->writeElement('a:lstStyle', null);
590
591        // a:p
592        $objWriter->startElement('a:p');
593
594        // a:pPr
595        $objWriter->startElement('a:pPr');
596        $objWriter->writeAttribute('algn', $subject->getAlignment()->getHorizontal());
597        $objWriter->writeAttribute('fontAlgn', $subject->getAlignment()->getVertical());
598        $objWriter->writeAttribute('marL', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginLeft()));
599        $objWriter->writeAttribute('marR', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginRight()));
600        $objWriter->writeAttribute('indent', CommonDrawing::pixelsToEmu($subject->getAlignment()->getIndent()));
601        $objWriter->writeAttribute('lvl', $subject->getAlignment()->getLevel());
602
603        // a:defRPr
604        $objWriter->startElement('a:defRPr');
605
606        $objWriter->writeAttribute('b', ($subject->getFont()->isBold() ? 'true' : 'false'));
607        $objWriter->writeAttribute('i', ($subject->getFont()->isItalic() ? 'true' : 'false'));
608        $objWriter->writeAttribute('strike', ($subject->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
609        $objWriter->writeAttribute('sz', ($subject->getFont()->getSize() * 100));
610        $objWriter->writeAttribute('u', $subject->getFont()->getUnderline());
611        $objWriter->writeAttributeIf($subject->getFont()->isSuperScript(), 'baseline', '300000');
612        $objWriter->writeAttributeIf($subject->getFont()->isSubScript(), 'baseline', '-250000');
613
614        // Font - a:solidFill
615        $objWriter->startElement('a:solidFill');
616
617        $this->writeColor($objWriter, $subject->getFont()->getColor());
618
619        $objWriter->endElement();
620
621        // Font - a:latin
622        $objWriter->startElement('a:latin');
623        $objWriter->writeAttribute('typeface', $subject->getFont()->getName());
624        $objWriter->endElement();
625
626        $objWriter->endElement();
627
628        $objWriter->endElement();
629
630        // a:endParaRPr
631        $objWriter->startElement('a:endParaRPr');
632        $objWriter->writeAttribute('lang', 'en-US');
633        $objWriter->writeAttribute('dirty', '0');
634        $objWriter->endElement();
635
636        $objWriter->endElement();
637
638        $objWriter->endElement();
639
640        $objWriter->endElement();
641    }
642
643    /**
644     * Write Layout.
645     *
646     * @param XMLWriter $objWriter XML Writer
647     * @param Legend|PlotArea|Title $subject
648     */
649    protected function writeLayout(XMLWriter $objWriter, $subject): void
650    {
651        // c:layout
652        $objWriter->startElement('c:layout');
653
654        // c:manualLayout
655        $objWriter->startElement('c:manualLayout');
656        // c:xMode
657        $objWriter->startElement('c:xMode');
658        $objWriter->writeAttribute('val', 'edge');
659        $objWriter->endElement();
660
661        // c:yMode
662        $objWriter->startElement('c:yMode');
663        $objWriter->writeAttribute('val', 'edge');
664        $objWriter->endElement();
665
666        if (0 != $subject->getOffsetX()) {
667            // c:x
668            $objWriter->startElement('c:x');
669            $objWriter->writeAttribute('val', $subject->getOffsetX());
670            $objWriter->endElement();
671        }
672
673        if (0 != $subject->getOffsetY()) {
674            // c:y
675            $objWriter->startElement('c:y');
676            $objWriter->writeAttribute('val', $subject->getOffsetY());
677            $objWriter->endElement();
678        }
679
680        if (0 != $subject->getWidth()) {
681            // c:w
682            $objWriter->startElement('c:w');
683            $objWriter->writeAttribute('val', $subject->getWidth());
684            $objWriter->endElement();
685        }
686
687        if (0 != $subject->getHeight()) {
688            // c:h
689            $objWriter->startElement('c:h');
690            $objWriter->writeAttribute('val', $subject->getHeight());
691            $objWriter->endElement();
692        }
693
694        $objWriter->endElement();
695        $objWriter->endElement();
696    }
697
698    /**
699     * Write Type Area.
700     *
701     * @param XMLWriter $objWriter XML Writer
702     * @param Chart\Type\Area $subject
703     * @param bool $includeSheet
704     */
705    protected function writeTypeArea(XMLWriter $objWriter, Area $subject, bool $includeSheet = false): void
706    {
707        // c:lineChart
708        $objWriter->startElement('c:areaChart');
709
710        // c:grouping
711        $objWriter->startElement('c:grouping');
712        $objWriter->writeAttribute('val', 'standard');
713        $objWriter->endElement();
714
715        // Write series
716        $seriesIndex = 0;
717        foreach ($subject->getSeries() as $series) {
718            // c:ser
719            $objWriter->startElement('c:ser');
720
721            // c:ser > c:idx
722            $objWriter->startElement('c:idx');
723            $objWriter->writeAttribute('val', $seriesIndex);
724            $objWriter->endElement();
725
726            // c:ser > c:order
727            $objWriter->startElement('c:order');
728            $objWriter->writeAttribute('val', $seriesIndex);
729            $objWriter->endElement();
730
731            // c:ser > c:tx
732            $objWriter->startElement('c:tx');
733            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
734            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
735            $objWriter->endElement();
736
737            // c:ser > c:dLbls
738            // @link : https://msdn.microsoft.com/en-us/library/documentformat.openxml.drawing.charts.areachartseries.aspx
739            $objWriter->startElement('c:dLbls');
740
741            // c:ser > c:dLbls > c:showVal
742            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
743
744            // c:ser > c:dLbls > c:showCatName
745            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
746
747            // c:ser > c:dLbls > c:showSerName
748            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
749
750            // c:ser > c:dLbls > c:showPercent
751            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
752
753            // c:ser > ##c:dLbls
754            $objWriter->endElement();
755
756            if (Fill::FILL_NONE != $series->getFill()->getFillType()) {
757                // c:spPr
758                $objWriter->startElement('c:spPr');
759                // Write fill
760                $this->writeFill($objWriter, $series->getFill());
761                // ## c:spPr
762                $objWriter->endElement();
763            }
764
765            // Write X axis data
766            $axisXData = array_keys($series->getValues());
767
768            // c:cat
769            $objWriter->startElement('c:cat');
770            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
771            $objWriter->endElement();
772
773            // Write Y axis data
774            $axisYData = array_values($series->getValues());
775
776            // c:val
777            $objWriter->startElement('c:val');
778            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
779            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
780            $objWriter->endElement();
781
782            $objWriter->endElement();
783
784            ++$seriesIndex;
785        }
786
787        // c:axId
788        $objWriter->startElement('c:axId');
789        $objWriter->writeAttribute('val', '52743552');
790        $objWriter->endElement();
791
792        // c:axId
793        $objWriter->startElement('c:axId');
794        $objWriter->writeAttribute('val', '52749440');
795        $objWriter->endElement();
796
797        $objWriter->endElement();
798    }
799
800    /**
801     * Write Type Bar.
802     *
803     * @param XMLWriter $objWriter XML Writer
804     * @param Chart\Type\Bar $subject
805     * @param bool $includeSheet
806     */
807    protected function writeTypeBar(XMLWriter $objWriter, Bar $subject, bool $includeSheet = false): void
808    {
809        // c:barChart
810        $objWriter->startElement('c:barChart');
811
812        // c:barDir
813        $objWriter->startElement('c:barDir');
814        $objWriter->writeAttribute('val', $subject->getBarDirection());
815        $objWriter->endElement();
816
817        // c:grouping
818        $objWriter->startElement('c:grouping');
819        $objWriter->writeAttribute('val', $subject->getBarGrouping());
820        $objWriter->endElement();
821
822        // Write series
823        $seriesIndex = 0;
824        foreach ($subject->getSeries() as $series) {
825            // c:ser
826            $objWriter->startElement('c:ser');
827
828            // c:idx
829            $objWriter->startElement('c:idx');
830            $objWriter->writeAttribute('val', $seriesIndex);
831            $objWriter->endElement();
832
833            // c:order
834            $objWriter->startElement('c:order');
835            $objWriter->writeAttribute('val', $seriesIndex);
836            $objWriter->endElement();
837
838            // c:tx
839            $objWriter->startElement('c:tx');
840            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
841            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
842            $objWriter->endElement();
843
844            // Fills for points?
845            $dataPointFills = $series->getDataPointFills();
846            foreach ($dataPointFills as $key => $value) {
847                // c:dPt
848                $objWriter->startElement('c:dPt');
849
850                // c:idx
851                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
852
853                if (Fill::FILL_NONE != $value->getFillType()) {
854                    // c:spPr
855                    $objWriter->startElement('c:spPr');
856                    // Write fill
857                    $this->writeFill($objWriter, $value);
858                    // ## c:spPr
859                    $objWriter->endElement();
860                }
861
862                // ## c:dPt
863                $objWriter->endElement();
864            }
865
866            // c:dLbls
867            $objWriter->startElement('c:dLbls');
868
869            if ($series->hasDlblNumFormat()) {
870                //c:numFmt
871                $objWriter->startElement('c:numFmt');
872                $objWriter->writeAttribute('formatCode', $series->getDlblNumFormat());
873                $objWriter->writeAttribute('sourceLinked', '0');
874                $objWriter->endElement();
875            }
876
877            // c:txPr
878            $objWriter->startElement('c:txPr');
879
880            // a:bodyPr
881            $objWriter->writeElement('a:bodyPr');
882
883            // a:lstStyle
884            $objWriter->writeElement('a:lstStyle');
885
886            // a:p
887            $objWriter->startElement('a:p');
888
889            // a:pPr
890            $objWriter->startElement('a:pPr');
891
892            // a:defRPr
893            $objWriter->startElement('a:defRPr');
894
895            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
896            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
897            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
898            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
899            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
900            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
901            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
902
903            // a:solidFill
904            $objWriter->startElement('a:solidFill');
905            $this->writeColor($objWriter, $series->getFont()->getColor());
906            // >a:solidFill
907            $objWriter->endElement();
908            // a:latin
909            $objWriter->startElement('a:latin');
910            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
911            // >a:latin
912            $objWriter->endElement();
913
914            // >a:defRPr
915            $objWriter->endElement();
916            // >a:pPr
917            $objWriter->endElement();
918
919            // a:endParaRPr
920            $objWriter->startElement('a:endParaRPr');
921            $objWriter->writeAttribute('lang', 'en-US');
922            $objWriter->writeAttribute('dirty', '0');
923            $objWriter->endElement();
924
925            // >a:p
926            $objWriter->endElement();
927            // >a:lstStyle
928            $objWriter->endElement();
929
930            // c:dLblPos
931            $this->writeElementWithValAttribute($objWriter, 'c:dLblPos', $series->getLabelPosition());
932
933            // c:showVal
934            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
935
936            // c:showCatName
937            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
938
939            // c:showSerName
940            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
941
942            // c:showPercent
943            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
944
945            // c:separator
946            $objWriter->writeElement('c:separator', $series->hasShowSeparator() ? $series->getSeparator() : '');
947
948            // c:showLeaderLines
949            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
950
951            $objWriter->endElement();
952
953            // c:spPr
954            if (Fill::FILL_NONE != $series->getFill()->getFillType()) {
955                // c:spPr
956                $objWriter->startElement('c:spPr');
957                // Write fill
958                $this->writeFill($objWriter, $series->getFill());
959                // ## c:spPr
960                $objWriter->endElement();
961            }
962
963            // Write X axis data
964            $axisXData = array_keys($series->getValues());
965
966            // c:cat
967            $objWriter->startElement('c:cat');
968            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
969            $objWriter->endElement();
970
971            // Write Y axis data
972            $axisYData = array_values($series->getValues());
973
974            // c:val
975            $objWriter->startElement('c:val');
976            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
977            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
978            $objWriter->endElement();
979
980            $objWriter->endElement();
981
982            ++$seriesIndex;
983        }
984
985        // c:gapWidth
986        $objWriter->startElement('c:gapWidth');
987        $objWriter->writeAttribute('val', $subject->getGapWidthPercent());
988        $objWriter->endElement();
989
990        // c:overlap
991        $objWriter->startElement('c:overlap');
992        $objWriter->writeAttribute('val', $subject->getOverlapWidthPercent());
993        $objWriter->endElement();
994
995        // c:axId
996        $objWriter->startElement('c:axId');
997        $objWriter->writeAttribute('val', '52743552');
998        $objWriter->endElement();
999
1000        // c:axId
1001        $objWriter->startElement('c:axId');
1002        $objWriter->writeAttribute('val', '52749440');
1003        $objWriter->endElement();
1004
1005        // c:extLst
1006        $objWriter->startElement('c:extLst');
1007        $objWriter->endElement();
1008
1009        $objWriter->endElement();
1010    }
1011
1012    /**
1013     * Write Type Bar3D.
1014     *
1015     * @param XMLWriter $objWriter XML Writer
1016     * @param Chart\Type\Bar3D $subject
1017     * @param bool $includeSheet
1018     */
1019    protected function writeTypeBar3D(XMLWriter $objWriter, Bar3D $subject, bool $includeSheet = false): void
1020    {
1021        // c:bar3DChart
1022        $objWriter->startElement('c:bar3DChart');
1023
1024        // c:barDir
1025        $objWriter->startElement('c:barDir');
1026        $objWriter->writeAttribute('val', $subject->getBarDirection());
1027        $objWriter->endElement();
1028
1029        // c:grouping
1030        $objWriter->startElement('c:grouping');
1031        $objWriter->writeAttribute('val', $subject->getBarGrouping());
1032        $objWriter->endElement();
1033
1034        // Write series
1035        $seriesIndex = 0;
1036        foreach ($subject->getSeries() as $series) {
1037            // c:ser
1038            $objWriter->startElement('c:ser');
1039
1040            // c:idx
1041            $objWriter->startElement('c:idx');
1042            $objWriter->writeAttribute('val', $seriesIndex);
1043            $objWriter->endElement();
1044
1045            // c:order
1046            $objWriter->startElement('c:order');
1047            $objWriter->writeAttribute('val', $seriesIndex);
1048            $objWriter->endElement();
1049
1050            // c:tx
1051            $objWriter->startElement('c:tx');
1052            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
1053            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1054            $objWriter->endElement();
1055
1056            // Fills for points?
1057            $dataPointFills = $series->getDataPointFills();
1058            foreach ($dataPointFills as $key => $value) {
1059                // c:dPt
1060                $objWriter->startElement('c:dPt');
1061
1062                // c:idx
1063                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
1064
1065                if (Fill::FILL_NONE != $value->getFillType()) {
1066                    // c:spPr
1067                    $objWriter->startElement('c:spPr');
1068                    // Write fill
1069                    $this->writeFill($objWriter, $value);
1070                    // ## c:spPr
1071                    $objWriter->endElement();
1072                }
1073
1074                // ## c:dPt
1075                $objWriter->endElement();
1076            }
1077
1078            // c:dLbls
1079            $objWriter->startElement('c:dLbls');
1080
1081            // c:txPr
1082            $objWriter->startElement('c:txPr');
1083
1084            // a:bodyPr
1085            $objWriter->writeElement('a:bodyPr', null);
1086
1087            // a:lstStyle
1088            $objWriter->writeElement('a:lstStyle', null);
1089
1090            // a:p
1091            $objWriter->startElement('a:p');
1092
1093            // a:pPr
1094            $objWriter->startElement('a:pPr');
1095
1096            // a:defRPr
1097            $objWriter->startElement('a:defRPr');
1098
1099            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1100            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1101            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1102            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1103            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1104            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1105            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1106
1107            // Font - a:solidFill
1108            $objWriter->startElement('a:solidFill');
1109
1110            $this->writeColor($objWriter, $series->getFont()->getColor());
1111
1112            $objWriter->endElement();
1113
1114            // Font - a:latin
1115            $objWriter->startElement('a:latin');
1116            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1117            $objWriter->endElement();
1118
1119            $objWriter->endElement();
1120
1121            $objWriter->endElement();
1122
1123            // a:endParaRPr
1124            $objWriter->startElement('a:endParaRPr');
1125            $objWriter->writeAttribute('lang', 'en-US');
1126            $objWriter->writeAttribute('dirty', '0');
1127            $objWriter->endElement();
1128
1129            $objWriter->endElement();
1130
1131            $objWriter->endElement();
1132
1133            // c:showVal
1134            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1135
1136            // c:showCatName
1137            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1138
1139            // c:showSerName
1140            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1141
1142            // c:showPercent
1143            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1144
1145            // c:showLeaderLines
1146            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1147
1148            $objWriter->endElement();
1149
1150            // c:spPr
1151            if (Fill::FILL_NONE != $series->getFill()->getFillType()) {
1152                // c:spPr
1153                $objWriter->startElement('c:spPr');
1154                // Write fill
1155                $this->writeFill($objWriter, $series->getFill());
1156                // ## c:spPr
1157                $objWriter->endElement();
1158            }
1159
1160            // Write X axis data
1161            $axisXData = array_keys($series->getValues());
1162
1163            // c:cat
1164            $objWriter->startElement('c:cat');
1165            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1166            $objWriter->endElement();
1167
1168            // Write Y axis data
1169            $axisYData = array_values($series->getValues());
1170
1171            // c:val
1172            $objWriter->startElement('c:val');
1173            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
1174            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1175            $objWriter->endElement();
1176
1177            $objWriter->endElement();
1178
1179            ++$seriesIndex;
1180        }
1181
1182        // c:gapWidth
1183        $objWriter->startElement('c:gapWidth');
1184        $objWriter->writeAttribute('val', $subject->getGapWidthPercent());
1185        $objWriter->endElement();
1186
1187        // c:axId
1188        $objWriter->startElement('c:axId');
1189        $objWriter->writeAttribute('val', '52743552');
1190        $objWriter->endElement();
1191
1192        // c:axId
1193        $objWriter->startElement('c:axId');
1194        $objWriter->writeAttribute('val', '52749440');
1195        $objWriter->endElement();
1196
1197        // c:axId
1198        $objWriter->startElement('c:axId');
1199        $objWriter->writeAttribute('val', '0');
1200        $objWriter->endElement();
1201
1202        $objWriter->endElement();
1203    }
1204
1205    /**
1206     * Write Type Pie.
1207     *
1208     * @param XMLWriter $objWriter XML Writer
1209     * @param Doughnut $subject
1210     * @param bool $includeSheet
1211     */
1212    protected function writeTypeDoughnut(XMLWriter $objWriter, Doughnut $subject, bool $includeSheet = false): void
1213    {
1214        // c:pieChart
1215        $objWriter->startElement('c:doughnutChart');
1216
1217        // c:varyColors
1218        $objWriter->startElement('c:varyColors');
1219        $objWriter->writeAttribute('val', '1');
1220        $objWriter->endElement();
1221
1222        // Write series
1223        $seriesIndex = 0;
1224        foreach ($subject->getSeries() as $series) {
1225            // c:ser
1226            $objWriter->startElement('c:ser');
1227
1228            // c:idx
1229            $objWriter->startElement('c:idx');
1230            $objWriter->writeAttribute('val', $seriesIndex);
1231            $objWriter->endElement();
1232
1233            // c:order
1234            $objWriter->startElement('c:order');
1235            $objWriter->writeAttribute('val', $seriesIndex);
1236            $objWriter->endElement();
1237
1238            // c:tx
1239            $objWriter->startElement('c:tx');
1240            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
1241            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1242            $objWriter->endElement();
1243
1244            // Fills for points?
1245            $dataPointFills = $series->getDataPointFills();
1246            foreach ($dataPointFills as $key => $value) {
1247                // c:dPt
1248                $objWriter->startElement('c:dPt');
1249                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
1250                // c:dPt/c:spPr
1251                $objWriter->startElement('c:spPr');
1252                $this->writeFill($objWriter, $value);
1253                // c:dPt/##c:spPr
1254                $objWriter->endElement();
1255                // ##c:dPt
1256                $objWriter->endElement();
1257            }
1258
1259            // Write X axis data
1260            $axisXData = array_keys($series->getValues());
1261
1262            // c:cat
1263            $objWriter->startElement('c:cat');
1264            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1265            $objWriter->endElement();
1266
1267            // Write Y axis data
1268            $axisYData = array_values($series->getValues());
1269
1270            // c:val
1271            $objWriter->startElement('c:val');
1272            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
1273            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1274            $objWriter->endElement();
1275
1276            $objWriter->endElement();
1277
1278            ++$seriesIndex;
1279        }
1280
1281        if (isset($series) && is_object($series) && $series instanceof Chart\Series) {
1282            // c:dLbls
1283            $objWriter->startElement('c:dLbls');
1284
1285            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
1286            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1287            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1288            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1289            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1290            $this->writeElementWithValAttribute($objWriter, 'c:showBubbleSize', '0');
1291            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1292
1293            if ($series->hasDlblNumFormat()) {
1294                //c:numFmt
1295                $objWriter->startElement('c:numFmt');
1296                $objWriter->writeAttribute('formatCode', $series->getDlblNumFormat());
1297                $objWriter->writeAttribute('sourceLinked', '0');
1298                $objWriter->endElement();
1299            }
1300
1301            // c:dLbls\c:txPr
1302            $objWriter->startElement('c:txPr');
1303            $objWriter->writeElement('a:bodyPr', null);
1304            $objWriter->writeElement('a:lstStyle', null);
1305
1306            // c:dLbls\c:txPr\a:p
1307            $objWriter->startElement('a:p');
1308
1309            // c:dLbls\c:txPr\a:p\a:pPr
1310            $objWriter->startElement('a:pPr');
1311
1312            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr
1313            $objWriter->startElement('a:defRPr');
1314            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1315            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1316            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1317            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1318            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1319            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1320            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1321
1322            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\a:solidFill
1323            $objWriter->startElement('a:solidFill');
1324            $this->writeColor($objWriter, $series->getFont()->getColor());
1325            $objWriter->endElement();
1326
1327            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\a:latin
1328            $objWriter->startElement('a:latin');
1329            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1330            $objWriter->endElement();
1331
1332            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\
1333            $objWriter->endElement();
1334            // c:dLbls\c:txPr\a:p\a:pPr\
1335            $objWriter->endElement();
1336
1337            // c:dLbls\c:txPr\a:p\a:endParaRPr
1338            $objWriter->startElement('a:endParaRPr');
1339            $objWriter->writeAttribute('lang', 'en-US');
1340            $objWriter->writeAttribute('dirty', '0');
1341            $objWriter->endElement();
1342
1343            // c:dLbls\c:txPr\a:p\
1344            $objWriter->endElement();
1345            // c:dLbls\c:txPr\
1346            $objWriter->endElement();
1347
1348            $separator = $series->getSeparator();
1349            if (!empty($separator) && PHP_EOL != $separator) {
1350                // c:dLbls\c:separator
1351                $objWriter->writeElement('c:separator', $separator);
1352            }
1353
1354            // c:dLbls\
1355            $objWriter->endElement();
1356        }
1357
1358        $this->writeElementWithValAttribute($objWriter, 'c:firstSliceAng', '0');
1359        $this->writeElementWithValAttribute($objWriter, 'c:holeSize', (string) $subject->getHoleSize());
1360
1361        $objWriter->endElement();
1362    }
1363
1364    /**
1365     * Write Type Pie.
1366     *
1367     * @param XMLWriter $objWriter XML Writer
1368     * @param Pie $subject
1369     * @param bool $includeSheet
1370     */
1371    protected function writeTypePie(XMLWriter $objWriter, Pie $subject, bool $includeSheet = false): void
1372    {
1373        // c:pieChart
1374        $objWriter->startElement('c:pieChart');
1375
1376        // c:varyColors
1377        $objWriter->startElement('c:varyColors');
1378        $objWriter->writeAttribute('val', '1');
1379        $objWriter->endElement();
1380
1381        // Write series
1382        $seriesIndex = 0;
1383        foreach ($subject->getSeries() as $series) {
1384            // c:ser
1385            $objWriter->startElement('c:ser');
1386
1387            // c:idx
1388            $objWriter->startElement('c:idx');
1389            $objWriter->writeAttribute('val', $seriesIndex);
1390            $objWriter->endElement();
1391
1392            // c:order
1393            $objWriter->startElement('c:order');
1394            $objWriter->writeAttribute('val', $seriesIndex);
1395            $objWriter->endElement();
1396
1397            // c:tx
1398            $objWriter->startElement('c:tx');
1399            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
1400            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1401            $objWriter->endElement();
1402
1403            // Fills for points?
1404            $dataPointFills = $series->getDataPointFills();
1405            foreach ($dataPointFills as $key => $value) {
1406                // c:dPt
1407                $objWriter->startElement('c:dPt');
1408                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
1409                // c:dPt/c:spPr
1410                $objWriter->startElement('c:spPr');
1411                $this->writeFill($objWriter, $value);
1412                // c:dPt/##c:spPr
1413                $objWriter->endElement();
1414                // ##c:dPt
1415                $objWriter->endElement();
1416            }
1417
1418            // c:dLbls
1419            $objWriter->startElement('c:dLbls');
1420
1421            if ($series->hasDlblNumFormat()) {
1422                //c:numFmt
1423                $objWriter->startElement('c:numFmt');
1424                $objWriter->writeAttribute('formatCode', $series->getDlblNumFormat());
1425                $objWriter->writeAttribute('sourceLinked', '0');
1426                $objWriter->endElement();
1427            }
1428
1429            // c:txPr
1430            $objWriter->startElement('c:txPr');
1431
1432            // a:bodyPr
1433            $objWriter->writeElement('a:bodyPr', null);
1434
1435            // a:lstStyle
1436            $objWriter->writeElement('a:lstStyle', null);
1437
1438            // a:p
1439            $objWriter->startElement('a:p');
1440
1441            // a:pPr
1442            $objWriter->startElement('a:pPr');
1443
1444            // a:defRPr
1445            $objWriter->startElement('a:defRPr');
1446
1447            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1448            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1449            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1450            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1451            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1452            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1453            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1454
1455            // Font - a:solidFill
1456            $objWriter->startElement('a:solidFill');
1457
1458            $this->writeColor($objWriter, $series->getFont()->getColor());
1459
1460            $objWriter->endElement();
1461
1462            // Font - a:latin
1463            $objWriter->startElement('a:latin');
1464            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1465            $objWriter->endElement();
1466
1467            $objWriter->endElement();
1468
1469            $objWriter->endElement();
1470
1471            // a:endParaRPr
1472            $objWriter->startElement('a:endParaRPr');
1473            $objWriter->writeAttribute('lang', 'en-US');
1474            $objWriter->writeAttribute('dirty', '0');
1475            $objWriter->endElement();
1476
1477            $objWriter->endElement();
1478
1479            $objWriter->endElement();
1480
1481            // c:dLblPos
1482            $this->writeElementWithValAttribute($objWriter, 'c:dLblPos', $series->getLabelPosition());
1483
1484            // c:showLegendKey
1485            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
1486
1487            // c:showVal
1488            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1489
1490            // c:showCatName
1491            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1492
1493            // c:showSerName
1494            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1495
1496            // c:showPercent
1497            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1498
1499            // c:showLeaderLines
1500            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1501
1502            $objWriter->endElement();
1503
1504            // Write X axis data
1505            $axisXData = array_keys($series->getValues());
1506
1507            // c:cat
1508            $objWriter->startElement('c:cat');
1509            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1510            $objWriter->endElement();
1511
1512            // Write Y axis data
1513            $axisYData = array_values($series->getValues());
1514
1515            // c:val
1516            $objWriter->startElement('c:val');
1517            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
1518            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1519            $objWriter->endElement();
1520
1521            $objWriter->endElement();
1522
1523            ++$seriesIndex;
1524        }
1525
1526        $objWriter->endElement();
1527    }
1528
1529    /**
1530     * Write Type Pie3D.
1531     *
1532     * @param XMLWriter $objWriter XML Writer
1533     * @param Pie3D $subject
1534     * @param bool $includeSheet
1535     */
1536    protected function writeTypePie3D(XMLWriter $objWriter, Pie3D $subject, bool $includeSheet = false): void
1537    {
1538        // c:pie3DChart
1539        $objWriter->startElement('c:pie3DChart');
1540
1541        // c:varyColors
1542        $objWriter->startElement('c:varyColors');
1543        $objWriter->writeAttribute('val', '1');
1544        $objWriter->endElement();
1545
1546        // Write series
1547        $seriesIndex = 0;
1548        foreach ($subject->getSeries() as $series) {
1549            // c:ser
1550            $objWriter->startElement('c:ser');
1551
1552            // c:idx
1553            $objWriter->startElement('c:idx');
1554            $objWriter->writeAttribute('val', $seriesIndex);
1555            $objWriter->endElement();
1556
1557            // c:order
1558            $objWriter->startElement('c:order');
1559            $objWriter->writeAttribute('val', $seriesIndex);
1560            $objWriter->endElement();
1561
1562            // c:tx
1563            $objWriter->startElement('c:tx');
1564            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
1565            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1566            $objWriter->endElement();
1567
1568            // c:explosion
1569            $objWriter->startElement('c:explosion');
1570            $objWriter->writeAttribute('val', $subject->getExplosion());
1571            $objWriter->endElement();
1572
1573            // Fills for points?
1574            $dataPointFills = $series->getDataPointFills();
1575            foreach ($dataPointFills as $key => $value) {
1576                // c:dPt
1577                $objWriter->startElement('c:dPt');
1578                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
1579                // c:dPt/c:spPr
1580                $objWriter->startElement('c:spPr');
1581                $this->writeFill($objWriter, $value);
1582                // c:dPt/##c:spPr
1583                $objWriter->endElement();
1584                // ##c:dPt
1585                $objWriter->endElement();
1586            }
1587
1588            // c:dLbls
1589            $objWriter->startElement('c:dLbls');
1590
1591            // c:txPr
1592            $objWriter->startElement('c:txPr');
1593
1594            // a:bodyPr
1595            $objWriter->writeElement('a:bodyPr', null);
1596
1597            // a:lstStyle
1598            $objWriter->writeElement('a:lstStyle', null);
1599
1600            // a:p
1601            $objWriter->startElement('a:p');
1602
1603            // a:pPr
1604            $objWriter->startElement('a:pPr');
1605
1606            // a:defRPr
1607            $objWriter->startElement('a:defRPr');
1608
1609            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1610            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1611            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1612            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1613            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1614            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1615            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1616
1617            // Font - a:solidFill
1618            $objWriter->startElement('a:solidFill');
1619
1620            $this->writeColor($objWriter, $series->getFont()->getColor());
1621
1622            $objWriter->endElement();
1623
1624            // Font - a:latin
1625            $objWriter->startElement('a:latin');
1626            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1627            $objWriter->endElement();
1628
1629            $objWriter->endElement();
1630
1631            $objWriter->endElement();
1632
1633            // a:endParaRPr
1634            $objWriter->startElement('a:endParaRPr');
1635            $objWriter->writeAttribute('lang', 'en-US');
1636            $objWriter->writeAttribute('dirty', '0');
1637            $objWriter->endElement();
1638
1639            $objWriter->endElement();
1640
1641            $objWriter->endElement();
1642
1643            // c:dLblPos
1644            $this->writeElementWithValAttribute($objWriter, 'c:dLblPos', $series->getLabelPosition());
1645
1646            // c:showVal
1647            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1648
1649            // c:showCatName
1650            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1651
1652            // c:showSerName
1653            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1654
1655            // c:showPercent
1656            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1657
1658            // c:showLeaderLines
1659            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1660
1661            $objWriter->endElement();
1662
1663            // Write X axis data
1664            $axisXData = array_keys($series->getValues());
1665
1666            // c:cat
1667            $objWriter->startElement('c:cat');
1668            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1669            $objWriter->endElement();
1670
1671            // Write Y axis data
1672            $axisYData = array_values($series->getValues());
1673
1674            // c:val
1675            $objWriter->startElement('c:val');
1676            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
1677            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1678            $objWriter->endElement();
1679
1680            $objWriter->endElement();
1681
1682            ++$seriesIndex;
1683        }
1684
1685        $objWriter->endElement();
1686    }
1687
1688    /**
1689     * Write Type Line.
1690     *
1691     * @param XMLWriter $objWriter XML Writer
1692     * @param Line $subject
1693     * @param bool $includeSheet
1694     */
1695    protected function writeTypeLine(XMLWriter $objWriter, Line $subject, bool $includeSheet = false): void
1696    {
1697        // c:lineChart
1698        $objWriter->startElement('c:lineChart');
1699
1700        // c:grouping
1701        $objWriter->startElement('c:grouping');
1702        $objWriter->writeAttribute('val', 'standard');
1703        $objWriter->endElement();
1704
1705        // Write series
1706        $seriesIndex = 0;
1707        foreach ($subject->getSeries() as $series) {
1708            // c:ser
1709            $objWriter->startElement('c:ser');
1710
1711            // c:idx
1712            $objWriter->startElement('c:idx');
1713            $objWriter->writeAttribute('val', $seriesIndex);
1714            $objWriter->endElement();
1715
1716            // c:order
1717            $objWriter->startElement('c:order');
1718            $objWriter->writeAttribute('val', $seriesIndex);
1719            $objWriter->endElement();
1720
1721            // c:tx
1722            $objWriter->startElement('c:tx');
1723            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
1724            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1725            $objWriter->endElement();
1726
1727            // c:spPr
1728            $objWriter->startElement('c:spPr');
1729            // Write fill
1730            $this->writeFill($objWriter, $series->getFill());
1731            // Write outline
1732            $this->writeOutline($objWriter, $series->getOutline());
1733            // ## c:spPr
1734            $objWriter->endElement();
1735
1736            // Marker
1737            $this->writeSeriesMarker($objWriter, $series->getMarker());
1738
1739            // c:dLbls
1740            $objWriter->startElement('c:dLbls');
1741
1742            // c:txPr
1743            $objWriter->startElement('c:txPr');
1744
1745            // a:bodyPr
1746            $objWriter->writeElement('a:bodyPr', null);
1747
1748            // a:lstStyle
1749            $objWriter->writeElement('a:lstStyle', null);
1750
1751            // a:p
1752            $objWriter->startElement('a:p');
1753
1754            // a:pPr
1755            $objWriter->startElement('a:pPr');
1756
1757            // a:defRPr
1758            $objWriter->startElement('a:defRPr');
1759
1760            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1761            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1762            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1763            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1764            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1765            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1766            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1767
1768            // Font - a:solidFill
1769            $objWriter->startElement('a:solidFill');
1770
1771            $this->writeColor($objWriter, $series->getFont()->getColor());
1772
1773            $objWriter->endElement();
1774
1775            // Font - a:latin
1776            $objWriter->startElement('a:latin');
1777            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1778            $objWriter->endElement();
1779
1780            $objWriter->endElement();
1781
1782            $objWriter->endElement();
1783
1784            // a:endParaRPr
1785            $objWriter->startElement('a:endParaRPr');
1786            $objWriter->writeAttribute('lang', 'en-US');
1787            $objWriter->writeAttribute('dirty', '0');
1788            $objWriter->endElement();
1789
1790            $objWriter->endElement();
1791
1792            $objWriter->endElement();
1793
1794            // c:showVal
1795            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1796
1797            // c:showCatName
1798            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1799
1800            // c:showSerName
1801            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1802
1803            // c:showPercent
1804            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1805
1806            // c:showLeaderLines
1807            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1808
1809            // > c:dLbls
1810            $objWriter->endElement();
1811
1812            // Write X axis data
1813            $axisXData = array_keys($series->getValues());
1814
1815            // c:cat
1816            $objWriter->startElement('c:cat');
1817            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1818            $objWriter->endElement();
1819
1820            // Write Y axis data
1821            $axisYData = array_values($series->getValues());
1822
1823            // c:val
1824            $objWriter->startElement('c:val');
1825            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
1826            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1827            $objWriter->endElement();
1828
1829            // c:smooth
1830            $objWriter->startElement('c:smooth');
1831            $objWriter->writeAttribute('val', $subject->isSmooth() ? '1' : '0');
1832            $objWriter->endElement();
1833
1834            $objWriter->endElement();
1835
1836            ++$seriesIndex;
1837        }
1838
1839        // c:marker
1840        $objWriter->startElement('c:marker');
1841        $objWriter->writeAttribute('val', '1');
1842        $objWriter->endElement();
1843
1844        // c:axId
1845        $objWriter->startElement('c:axId');
1846        $objWriter->writeAttribute('val', '52743552');
1847        $objWriter->endElement();
1848
1849        // c:axId
1850        $objWriter->startElement('c:axId');
1851        $objWriter->writeAttribute('val', '52749440');
1852        $objWriter->endElement();
1853
1854        $objWriter->endElement();
1855    }
1856
1857    /**
1858     * Write Type Radar
1859     *
1860     * @param XMLWriter $objWriter XML Writer
1861     * @param Radar $subject
1862     * @param bool $includeSheet
1863     */
1864    protected function writeTypeRadar(XMLWriter $objWriter, Radar $subject, bool $includeSheet = false): void
1865    {
1866        // c:scatterChart
1867        $objWriter->startElement('c:radarChart');
1868
1869        // c:radarStyle
1870        $objWriter->startElement('c:radarStyle');
1871        $objWriter->writeAttribute('val', 'marker');
1872        $objWriter->endElement();
1873
1874        // c:varyColors
1875        $objWriter->startElement('c:varyColors');
1876        $objWriter->writeAttribute('val', '0');
1877        $objWriter->endElement();
1878
1879        // Write series
1880        $seriesIndex = 0;
1881        foreach ($subject->getSeries() as $series) {
1882            // c:ser
1883            $objWriter->startElement('c:ser');
1884
1885            // c:idx
1886            $objWriter->startElement('c:idx');
1887            $objWriter->writeAttribute('val', $seriesIndex);
1888            $objWriter->endElement();
1889
1890            // c:order
1891            $objWriter->startElement('c:order');
1892            $objWriter->writeAttribute('val', $seriesIndex);
1893            $objWriter->endElement();
1894
1895            // c:tx
1896            $objWriter->startElement('c:tx');
1897            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
1898            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1899            $objWriter->endElement();
1900
1901            // Marker
1902            $this->writeSeriesMarker($objWriter, $series->getMarker());
1903
1904            // c:dLbls
1905            $objWriter->startElement('c:dLbls');
1906
1907            // c:txPr
1908            $objWriter->startElement('c:txPr');
1909
1910            // a:bodyPr
1911            $objWriter->writeElement('a:bodyPr', null);
1912
1913            // a:lstStyle
1914            $objWriter->writeElement('a:lstStyle', null);
1915
1916            // a:p
1917            $objWriter->startElement('a:p');
1918
1919            // a:pPr
1920            $objWriter->startElement('a:pPr');
1921
1922            // a:defRPr
1923            $objWriter->startElement('a:defRPr');
1924
1925            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1926            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1927            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1928            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1929            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1930            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '30000');
1931            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-25000');
1932
1933            // Font - a:solidFill
1934            $objWriter->startElement('a:solidFill');
1935
1936            $this->writeColor($objWriter, $series->getFont()->getColor());
1937
1938            $objWriter->endElement();
1939
1940            // Font - a:latin
1941            $objWriter->startElement('a:latin');
1942            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1943            $objWriter->endElement();
1944
1945            $objWriter->endElement();
1946
1947            $objWriter->endElement();
1948
1949            // a:endParaRPr
1950            $objWriter->startElement('a:endParaRPr');
1951            $objWriter->writeAttribute('lang', 'en-US');
1952            $objWriter->writeAttribute('dirty', '0');
1953            $objWriter->endElement();
1954
1955            $objWriter->endElement();
1956
1957            $objWriter->endElement();
1958
1959            // c:showLegendKey
1960            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
1961
1962            // c:showVal
1963            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1964
1965            // c:showCatName
1966            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1967
1968            // c:showSerName
1969            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1970
1971            // c:showPercent
1972            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1973
1974            // c:showLeaderLines
1975            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1976
1977            $objWriter->endElement();
1978
1979            // c:spPr
1980            $objWriter->startElement('c:spPr');
1981            // Write fill
1982            $this->writeFill($objWriter, $series->getFill());
1983            // Write outline
1984            $this->writeOutline($objWriter, $series->getOutline());
1985            // ## c:spPr
1986            $objWriter->endElement();
1987
1988            // Write X axis data
1989            $axisXData = array_keys($series->getValues());
1990
1991            // c:cat
1992            $objWriter->startElement('c:cat');
1993            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1994            $objWriter->endElement();
1995
1996            // Write Y axis data
1997            $axisYData = array_values($series->getValues());
1998
1999            // c:val
2000            $objWriter->startElement('c:val');
2001            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
2002            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
2003            $objWriter->endElement();
2004
2005            // c:smooth
2006            $objWriter->startElement('c:smooth');
2007            $objWriter->writeAttribute('val', '0');
2008            $objWriter->endElement();
2009
2010            $objWriter->endElement();
2011
2012            ++$seriesIndex;
2013        }
2014
2015        // c:axId
2016        $objWriter->startElement('c:axId');
2017        $objWriter->writeAttribute('val', '52743552');
2018        $objWriter->endElement();
2019
2020        // c:axId
2021        $objWriter->startElement('c:axId');
2022        $objWriter->writeAttribute('val', '52749440');
2023        $objWriter->endElement();
2024
2025        $objWriter->endElement();
2026    }
2027
2028    /**
2029     * Write Type Scatter
2030     *
2031     * @param XMLWriter $objWriter
2032     * @param Scatter $subject
2033     * @param bool $includeSheet
2034     */
2035    protected function writeTypeScatter(XMLWriter $objWriter, Scatter $subject, bool $includeSheet = false): void
2036    {
2037        // c:scatterChart
2038        $objWriter->startElement('c:scatterChart');
2039
2040        // c:scatterStyle
2041        $objWriter->startElement('c:scatterStyle');
2042        $objWriter->writeAttribute('val', 'lineMarker');
2043        $objWriter->endElement();
2044
2045        // c:varyColors
2046        $objWriter->startElement('c:varyColors');
2047        $objWriter->writeAttribute('val', '0');
2048        $objWriter->endElement();
2049
2050        // Write series
2051        $seriesIndex = 0;
2052        foreach ($subject->getSeries() as $series) {
2053            // c:ser
2054            $objWriter->startElement('c:ser');
2055
2056            // c:idx
2057            $objWriter->startElement('c:idx');
2058            $objWriter->writeAttribute('val', $seriesIndex);
2059            $objWriter->endElement();
2060
2061            // c:order
2062            $objWriter->startElement('c:order');
2063            $objWriter->writeAttribute('val', $seriesIndex);
2064            $objWriter->endElement();
2065
2066            // c:tx
2067            $objWriter->startElement('c:tx');
2068            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
2069            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
2070            $objWriter->endElement();
2071
2072            // c:spPr
2073            $objWriter->startElement('c:spPr');
2074            // Write fill
2075            $this->writeFill($objWriter, $series->getFill());
2076            // Write outline
2077            $this->writeOutline($objWriter, $series->getOutline());
2078            // ## c:spPr
2079            $objWriter->endElement();
2080
2081            // Marker
2082            $this->writeSeriesMarker($objWriter, $series->getMarker());
2083
2084            // c:dLbls
2085            $objWriter->startElement('c:dLbls');
2086
2087            // c:txPr
2088            $objWriter->startElement('c:txPr');
2089
2090            // a:bodyPr
2091            $objWriter->writeElement('a:bodyPr', null);
2092
2093            // a:lstStyle
2094            $objWriter->writeElement('a:lstStyle', null);
2095
2096            // a:p
2097            $objWriter->startElement('a:p');
2098
2099            // a:pPr
2100            $objWriter->startElement('a:pPr');
2101
2102            // a:defRPr
2103            $objWriter->startElement('a:defRPr');
2104
2105            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
2106            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
2107            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
2108            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
2109            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
2110            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
2111            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
2112
2113            // Font - a:solidFill
2114            $objWriter->startElement('a:solidFill');
2115
2116            $this->writeColor($objWriter, $series->getFont()->getColor());
2117
2118            $objWriter->endElement();
2119
2120            // Font - a:latin
2121            $objWriter->startElement('a:latin');
2122            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
2123            $objWriter->endElement();
2124
2125            $objWriter->endElement();
2126
2127            $objWriter->endElement();
2128
2129            // a:endParaRPr
2130            $objWriter->startElement('a:endParaRPr');
2131            $objWriter->writeAttribute('lang', 'en-US');
2132            $objWriter->writeAttribute('dirty', '0');
2133            $objWriter->endElement();
2134
2135            $objWriter->endElement();
2136
2137            $objWriter->endElement();
2138
2139            // c:showLegendKey
2140            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
2141
2142            // c:showVal
2143            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
2144
2145            // c:showCatName
2146            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
2147
2148            // c:showSerName
2149            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
2150
2151            // c:showPercent
2152            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
2153
2154            // c:separator
2155            $separator = $series->getSeparator();
2156            if (!empty($separator) && PHP_EOL != $separator) {
2157                // c:dLbls\c:separator
2158                $objWriter->writeElement('c:separator', $separator);
2159            }
2160
2161            // c:showLeaderLines
2162            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
2163
2164            $objWriter->endElement();
2165
2166            // Write X axis data
2167            $axisXData = array_keys($series->getValues());
2168
2169            // c:xVal
2170            $objWriter->startElement('c:xVal');
2171            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
2172            $objWriter->endElement();
2173
2174            // Write Y axis data
2175            $axisYData = array_values($series->getValues());
2176
2177            // c:yVal
2178            $objWriter->startElement('c:yVal');
2179            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
2180            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
2181            $objWriter->endElement();
2182
2183            // c:smooth
2184            $objWriter->startElement('c:smooth');
2185            $objWriter->writeAttribute('val', $subject->isSmooth() ? '1' : '0');
2186            $objWriter->endElement();
2187
2188            $objWriter->endElement();
2189
2190            ++$seriesIndex;
2191        }
2192
2193        // c:axId
2194        $objWriter->startElement('c:axId');
2195        $objWriter->writeAttribute('val', '52743552');
2196        $objWriter->endElement();
2197
2198        // c:axId
2199        $objWriter->startElement('c:axId');
2200        $objWriter->writeAttribute('val', '52749440');
2201        $objWriter->endElement();
2202
2203        $objWriter->endElement();
2204    }
2205
2206    /**
2207     * Write chart relationships to XML format.
2208     *
2209     * @param Chart $pChart
2210     *
2211     * @return string XML Output
2212     */
2213    protected function writeChartRelationships(Chart $pChart): string
2214    {
2215        // Create XML writer
2216        $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
2217
2218        // XML header
2219        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
2220
2221        // Relationships
2222        $objWriter->startElement('Relationships');
2223        $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');
2224
2225        // Write spreadsheet relationship?
2226        if ($pChart->hasIncludedSpreadsheet()) {
2227            $this->writeRelationship($objWriter, 1, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/package', '../embeddings/' . $pChart->getIndexedFilename() . '.xlsx');
2228        }
2229
2230        $objWriter->endElement();
2231
2232        // Return
2233        return $objWriter->getData();
2234    }
2235
2236    /**
2237     * @param XMLWriter $objWriter
2238     * @param Chart\Marker $marker
2239     */
2240    protected function writeSeriesMarker(XMLWriter $objWriter, Chart\Marker $marker): void
2241    {
2242        // c:marker
2243        $objWriter->startElement('c:marker');
2244        // c:marker > c:symbol
2245        $objWriter->startElement('c:symbol');
2246        $objWriter->writeAttribute('val', $marker->getSymbol());
2247        $objWriter->endElement();
2248
2249        // Size if different of none
2250        if (Chart\Marker::SYMBOL_NONE != $marker->getSymbol()) {
2251            $markerSize = (int) $marker->getSize();
2252            if ($markerSize < 2) {
2253                $markerSize = 2;
2254            }
2255            if ($markerSize > 72) {
2256                $markerSize = 72;
2257            }
2258
2259            /*
2260             * c:marker > c:size
2261             * Size in points
2262             * @link : https://msdn.microsoft.com/en-us/library/hh658135(v=office.12).aspx
2263             */
2264            $objWriter->startElement('c:size');
2265            $objWriter->writeAttribute('val', $markerSize);
2266            $objWriter->endElement();
2267        }
2268
2269        // // c:marker > c:spPr
2270        $objWriter->startElement('c:spPr');
2271        $this->writeFill($objWriter, $marker->getFill());
2272        $this->writeBorder($objWriter, $marker->getBorder(), '', true);
2273        $objWriter->endElement();
2274
2275        // > c:marker
2276        $objWriter->endElement();
2277    }
2278
2279    /**
2280     * @param XMLWriter $objWriter
2281     * @param Chart\Axis $oAxis
2282     * @param string $typeAxis
2283     * @param Chart\Type\AbstractType $typeChart
2284     */
2285    protected function writeAxis(XMLWriter $objWriter, Chart\Axis $oAxis, string $typeAxis, Chart\Type\AbstractType $typeChart): void
2286    {
2287        if (Chart\Axis::AXIS_X != $typeAxis && Chart\Axis::AXIS_Y != $typeAxis) {
2288            return;
2289        }
2290
2291        $crossesAt = $oAxis->getCrossesAt();
2292        $orientation = $oAxis->isReversedOrder() ? 'maxMin' : 'minMax';
2293
2294        if (Chart\Axis::AXIS_X == $typeAxis) {
2295            $mainElement = 'c:catAx';
2296            $axIdVal = '52743552';
2297            $axPosVal = $crossesAt === 'max' ? 't' : 'b';
2298            $crossAxVal = '52749440';
2299        } else {
2300            $mainElement = 'c:valAx';
2301            $axIdVal = '52749440';
2302            $axPosVal = $crossesAt === 'max' ? 'r' : 'l';
2303            $crossAxVal = '52743552';
2304        }
2305
2306        // $mainElement
2307        $objWriter->startElement($mainElement);
2308
2309        // $mainElement > c:axId
2310        $objWriter->startElement('c:axId');
2311        $objWriter->writeAttribute('val', $axIdVal);
2312        $objWriter->endElement();
2313
2314        // $mainElement > c:scaling
2315        $objWriter->startElement('c:scaling');
2316
2317        // $mainElement > c:scaling > c:orientation
2318        $objWriter->startElement('c:orientation');
2319        $objWriter->writeAttribute('val', $orientation);
2320        $objWriter->endElement();
2321
2322        if (null != $oAxis->getMaxBounds()) {
2323            $objWriter->startElement('c:max');
2324            $objWriter->writeAttribute('val', $oAxis->getMaxBounds());
2325            $objWriter->endElement();
2326        }
2327
2328        if (null != $oAxis->getMinBounds()) {
2329            $objWriter->startElement('c:min');
2330            $objWriter->writeAttribute('val', $oAxis->getMinBounds());
2331            $objWriter->endElement();
2332        }
2333
2334        // $mainElement > ##c:scaling
2335        $objWriter->endElement();
2336
2337        // $mainElement > c:delete
2338        $objWriter->startElement('c:delete');
2339        $objWriter->writeAttribute('val', $oAxis->isVisible() ? '0' : '1');
2340        $objWriter->endElement();
2341
2342        // $mainElement > c:axPos
2343        $objWriter->startElement('c:axPos');
2344        $objWriter->writeAttribute('val', $axPosVal);
2345        $objWriter->endElement();
2346
2347        $oMajorGridlines = $oAxis->getMajorGridlines();
2348        if ($oMajorGridlines instanceof Gridlines) {
2349            $objWriter->startElement('c:majorGridlines');
2350
2351            $this->writeAxisGridlines($objWriter, $oMajorGridlines);
2352
2353            $objWriter->endElement();
2354        }
2355
2356        $oMinorGridlines = $oAxis->getMinorGridlines();
2357        if ($oMinorGridlines instanceof Gridlines) {
2358            $objWriter->startElement('c:minorGridlines');
2359
2360            $this->writeAxisGridlines($objWriter, $oMinorGridlines);
2361
2362            $objWriter->endElement();
2363        }
2364
2365        if ('' != $oAxis->getTitle()) {
2366            // c:title
2367            $objWriter->startElement('c:title');
2368
2369            // c:tx
2370            $objWriter->startElement('c:tx');
2371
2372            // c:rich
2373            $objWriter->startElement('c:rich');
2374
2375            // a:bodyPr
2376            $objWriter->startElement('a:bodyPr');
2377            $objWriter->writeAttributeIf($oAxis->getTitleRotation() != 0, 'rot', CommonDrawing::degreesToAngle((int) $oAxis->getTitleRotation()));
2378            $objWriter->endElement();
2379
2380            // a:lstStyle
2381            $objWriter->writeElement('a:lstStyle', null);
2382
2383            // a:p
2384            $objWriter->startElement('a:p');
2385
2386            // a:pPr
2387            $objWriter->startElement('a:pPr');
2388
2389            // a:defRPr
2390            $objWriter->startElement('a:defRPr');
2391
2392            $objWriter->writeAttribute('b', ($oAxis->getFont()->isBold() ? 'true' : 'false'));
2393            $objWriter->writeAttribute('i', ($oAxis->getFont()->isItalic() ? 'true' : 'false'));
2394            $objWriter->writeAttribute('strike', ($oAxis->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
2395            $objWriter->writeAttribute('sz', ($oAxis->getFont()->getSize() * 100));
2396            $objWriter->writeAttribute('u', $oAxis->getFont()->getUnderline());
2397            $objWriter->writeAttributeIf($oAxis->getFont()->isSuperScript(), 'baseline', '300000');
2398            $objWriter->writeAttributeIf($oAxis->getFont()->isSubScript(), 'baseline', '-250000');
2399
2400            // Font - a:solidFill
2401            $objWriter->startElement('a:solidFill');
2402            $this->writeColor($objWriter, $oAxis->getFont()->getColor());
2403            $objWriter->endElement();
2404
2405            // Font - a:latin
2406            $objWriter->startElement('a:latin');
2407            $objWriter->writeAttribute('typeface', $oAxis->getFont()->getName());
2408            $objWriter->endElement();
2409
2410            $objWriter->endElement();
2411
2412            // ## a:pPr
2413            $objWriter->endElement();
2414
2415            // a:r
2416            $objWriter->startElement('a:r');
2417
2418            // a:rPr
2419            $objWriter->startElement('a:rPr');
2420            $objWriter->writeAttribute('lang', 'en-US');
2421            $objWriter->writeAttribute('dirty', '0');
2422            $objWriter->endElement();
2423
2424            // a:t
2425            $objWriter->writeElement('a:t', $oAxis->getTitle());
2426
2427            // ## a:r
2428            $objWriter->endElement();
2429
2430            // a:endParaRPr
2431            $objWriter->startElement('a:endParaRPr');
2432            $objWriter->writeAttribute('lang', 'en-US');
2433            $objWriter->writeAttribute('dirty', '0');
2434            $objWriter->endElement();
2435
2436            // ## a:p
2437            $objWriter->endElement();
2438
2439            // ## c:rich
2440            $objWriter->endElement();
2441
2442            // ## c:tx
2443            $objWriter->endElement();
2444
2445            // ## c:title
2446            $objWriter->endElement();
2447        }
2448
2449        // c:numFmt
2450        $objWriter->startElement('c:numFmt');
2451        $objWriter->writeAttribute('formatCode', $oAxis->getFormatCode());
2452        $objWriter->writeAttribute('sourceLinked', '1');
2453        $objWriter->endElement();
2454
2455        // c:majorTickMark
2456        $objWriter->startElement('c:majorTickMark');
2457        $objWriter->writeAttribute('val', $oAxis->getMajorTickMark());
2458        $objWriter->endElement();
2459
2460        // c:minorTickMark
2461        $objWriter->startElement('c:minorTickMark');
2462        $objWriter->writeAttribute('val', $oAxis->getMinorTickMark());
2463        $objWriter->endElement();
2464
2465        // c:tickLblPos
2466        $objWriter->startElement('c:tickLblPos');
2467        $objWriter->writeAttribute('val', $oAxis->getTickLabelPosition());
2468        $objWriter->endElement();
2469
2470        // c:spPr
2471        $objWriter->startElement('c:spPr');
2472        // Outline
2473        $this->writeOutline($objWriter, $oAxis->getOutline());
2474        // ##c:spPr
2475        $objWriter->endElement();
2476
2477        // c:crossAx
2478        $objWriter->startElement('c:crossAx');
2479        $objWriter->writeAttribute('val', $crossAxVal);
2480        $objWriter->endElement();
2481
2482        // c:crosses "autoZero" | "min" | "max" | custom string value
2483        if (in_array($crossesAt, ['autoZero', 'min', 'max'])) {
2484            $objWriter->startElement('c:crosses');
2485            $objWriter->writeAttribute('val', $crossesAt);
2486            $objWriter->endElement();
2487        } else {
2488            $objWriter->startElement('c:crossesAt');
2489            $objWriter->writeAttribute('val', $crossesAt);
2490            $objWriter->endElement();
2491        }
2492
2493        if (Chart\Axis::AXIS_X == $typeAxis) {
2494            // c:lblAlgn
2495            $objWriter->startElement('c:lblAlgn');
2496            $objWriter->writeAttribute('val', 'ctr');
2497            $objWriter->endElement();
2498
2499            // c:lblOffset
2500            $objWriter->startElement('c:lblOffset');
2501            $objWriter->writeAttribute('val', '100');
2502            $objWriter->endElement();
2503
2504            // c:majorUnit
2505            if ($oAxis->getMajorUnit() != null) {
2506                $objWriter->startElement('c:tickLblSkip');
2507                $objWriter->writeAttribute('val', $oAxis->getMajorUnit());
2508                $objWriter->endElement();
2509            }
2510        }
2511
2512        if (Chart\Axis::AXIS_Y == $typeAxis) {
2513            // c:crossBetween
2514            $objWriter->startElement('c:crossBetween');
2515            // midCat : Position Axis On Tick Marks
2516            // between : Between Tick Marks
2517            if ($typeChart instanceof Area) {
2518                $objWriter->writeAttribute('val', 'midCat');
2519            } else {
2520                $objWriter->writeAttribute('val', 'between');
2521            }
2522            $objWriter->endElement();
2523
2524            // c:majorUnit
2525            if (null != $oAxis->getMajorUnit()) {
2526                $objWriter->startElement('c:majorUnit');
2527                $objWriter->writeAttribute('val', $oAxis->getMajorUnit());
2528                $objWriter->endElement();
2529            }
2530
2531            // c:minorUnit
2532            if (null != $oAxis->getMinorUnit()) {
2533                $objWriter->startElement('c:minorUnit');
2534                $objWriter->writeAttribute('val', $oAxis->getMinorUnit());
2535                $objWriter->endElement();
2536            }
2537        }
2538
2539        $objWriter->endElement();
2540    }
2541
2542    /**
2543     * @param XMLWriter $objWriter
2544     * @param Gridlines $oGridlines
2545     */
2546    protected function writeAxisGridlines(XMLWriter $objWriter, Gridlines $oGridlines): void
2547    {
2548        // c:spPr
2549        $objWriter->startElement('c:spPr');
2550
2551        // Outline
2552        $this->writeOutline($objWriter, $oGridlines->getOutline());
2553
2554        // ##c:spPr
2555        $objWriter->endElement();
2556    }
2557}